package validator

import (
	"fmt"
	"ubt-rbac-service/internal/core/convert"
	"reflect"
	"regexp"
	"strings"
)

// 调用：str := ValidateStruct(user)

// validator 验证接口
type validator interface {
	validate(interface{}) (bool, error)
}

// blankValidator 空变量结构体
type blankValidator struct{}

// validate 校验实现
func (v *blankValidator) validate(_ interface{}) (bool, error) {
	return true, nil
}

// stringValidator 字符串变量结构体
type stringValidator struct {
	Name string
	Type string
	Min  int
	Max  int
}

// validate 校验实现
func (v *stringValidator) validate(val interface{}) (bool, error) {
	size := len(val.(string))
	if size == 0 {
		return false, fmt.Errorf("%v不能为空", v.Name)
	}
	if v.Min > 0 && size < v.Min && v.Type == "string" {
		return false, fmt.Errorf("%v的长度必须大于%v", v.Name, v.Min)
	}
	if v.Max > 0 && size > v.Max && v.Type == "string" {
		return false, fmt.Errorf("%v的长度必须小于%v", v.Name, v.Max)
	}
	return true, nil
}

// numberValidator 数字变量结构体
type numberValidator struct {
	Name string
	Type string
	Min  int
	Max  int
}

// validate 校验实现
func (v *numberValidator) validate(val interface{}) (bool, error) {
	size := val.(int)
	if size == 0 {
		return false, fmt.Errorf("对不起，%v不能为空，请检查！", v.Name)
	}
	if v.Min > 0 && size < v.Min && v.Type == "number" {
		return false, fmt.Errorf("对不起，%v必须大于%v，请检查！", v.Name, v.Min)
	}
	if v.Max > 0 && size > v.Max && v.Type == "number" {
		return false, fmt.Errorf("对不起，%v必须小于%v，请检查！", v.Name, v.Max)
	}
	return true, nil
}

// emailValidator 邮箱变量结构体
type emailValidator struct {
	Name string
}

// validate 校验实现
func (v *emailValidator) validate(val interface{}) (bool, error) {
	var mailRe = regexp.MustCompile(`^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$`)
	if !mailRe.MatchString(val.(string)) {
		return false, fmt.Errorf("对不起，%v不是有效的邮箱地址，请检查！", v.Name)
	}
	return true, nil
}

func getValidatorFromTag(tag string) validator {
	args := strings.Split(tag, ",")
	length := len(args)
	if length > 1 {
		switch args[1] {
		case "string":
			vdtStr := &stringValidator{Name: args[0], Type: args[1]}
			if length == 3 {
				kv := strings.Split(args[2], "=")
				switch kv[0] {
				case "min":
					vdtStr.Min = convert.Str2int(kv[1])
				case "max":
					vdtStr.Max = convert.Str2int(kv[1])
				}
			}
			if length == 4 {
				kv1 := strings.Split(args[2], "=")
				kv2 := strings.Split(args[3], "=")
				vdtStr.Min = convert.Str2int(kv1[1])
				vdtStr.Max = convert.Str2int(kv2[1])
			}
			return vdtStr
		case "number":
			vdtStr := &numberValidator{Name: args[0], Type: args[1]}
			if length == 3 {
				kv := strings.Split(args[2], "=")
				switch kv[0] {
				case "min":
					vdtStr.Min = convert.Str2int(kv[1])
				case "max":
					vdtStr.Max = convert.Str2int(kv[1])
				}
			}
			if length == 4 {
				kv1 := strings.Split(args[2], "=")
				kv2 := strings.Split(args[3], "=")
				vdtStr.Min = convert.Str2int(kv1[1])
				vdtStr.Max = convert.Str2int(kv2[1])
			}
			return vdtStr
		case "email":
			return &emailValidator{Name: args[0]}
		}
	}
	return &blankValidator{}
}

// ValidateStruct 结构体校验
func ValidateStruct(s interface{}) string {
	var errStr string
	v := reflect.ValueOf(s)
	if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
		v = v.Elem()
	}
	for i := 0; i < v.NumField(); i++ {
		field := v.Field(i)
		fieldKind := field.Kind()
		if fieldKind == reflect.String || (fieldKind == reflect.Ptr && field.Elem().Kind() == reflect.String) {
			typeField := v.Type().Field(i)
			tag := typeField.Tag.Get("v")
			if tag == "" || tag == "-" {
				continue
			}
			vdtStruct := getValidatorFromTag(tag)
			valid, err := vdtStruct.validate(v.Field(i).Interface())
			if !valid && err != nil {
				errStr = err.Error()
				break
			}
			continue
		}
		if fieldKind == reflect.Int || (fieldKind == reflect.Ptr && field.Elem().Kind() == reflect.Int) {
			typeField := v.Type().Field(i)
			tag := typeField.Tag.Get("v")
			if tag == "" || tag == "-" {
				continue
			}
			vdtStruct := getValidatorFromTag(tag)
			valid, err := vdtStruct.validate(v.Field(i).Interface())
			if !valid && err != nil {
				errStr = err.Error()
				break
			}
			continue
		}
		if fieldKind == reflect.Ptr && field.Elem().Kind() == reflect.Struct {
			if field.CanInterface() {
				ValidateStruct(field.Interface())
				tag := v.Type().Field(i).Tag.Get("v")
				if tag == "" || tag == "-" {
					continue
				}
				vdtStruct := getValidatorFromTag(tag)
				valid, err := vdtStruct.validate(v.Field(i).Interface())
				if !valid && err != nil {
					errStr = err.Error()
					break
				}
			}
			continue
		}
	}
	return errStr
}
